package engine;


import common.Log;

import platform.PlatformFactory;
import platform.Platform_I;
import engine.audio.AudioManager;
import engine.input.KeyQueue_I;
import engine.time.Timer;
import engine.video.blit.PixelBuffer_I;
import engine.filesystem.ResourceManager;
import engine.game.Game_I;
import engine.message.MessageSystem;

// TODO: Engine Stub
public final class Engine {
	// Singleton static constructor.
	public static Engine getEngine() {
		if (_Engine == null) {
			_Engine = new Engine();
		}
		return _Engine;
	}
	private static Engine _Engine;
	private Engine() {
		// CtoR Stub
	}
	// Subsystems --------------------------------------------------------------

	private Timer _Time;
	private PixelBuffer_I _ScreenBuffer;
	private AudioManager _AudioManager;
	private KeyQueue_I _KeyboardQueue;
	private MessageSystem _MessageSystem;
	private ResourceManager _ResourceManager;
	private Game_I _GameInstance;
	private Game_I _NextGameInstance;
	
	public void setNextGame(Game_I gameInstance) {
		_NextGameInstance = gameInstance;
	}
	private void pumpGame(Game_I game, int elapsed) {
		if(game == null && _NextGameInstance == null) {
			Log.error("Missing GameInstance, cannot continue.");
			throw new IllegalStateException();
		}
		
		if(_NextGameInstance == null) {
			if(game.execute(this, elapsed) == false) {
				Log.error("Game execution error.");
				throw new IllegalStateException();
			}
		} else {
			// Shutdown the old game instance.
			if(game != null && game.shutdown(this) == false) {
				Log.error("Game shutdown error.");
				throw new IllegalStateException();
			}
			// Swap them and initialize the new one.
			_GameInstance = _NextGameInstance;
			_NextGameInstance = null;
			if(_GameInstance.initialize(this) == false) {
				Log.error("Game initialization error.");
				throw new IllegalStateException();
			}
		}
	}
	
	public Timer getTimer() {
		return _Time;
	}
	public KeyQueue_I getKeyboardQueue() {
		return _KeyboardQueue;
	}
	
	public PixelBuffer_I getScreenBuffer() {
		return _ScreenBuffer;
	}
	public AudioManager getAudioManager() {
		return _AudioManager;
	}
	
	public MessageSystem getMessageSystem() {
		return _MessageSystem;
	}
	public ResourceManager getResourceManager() {
		return _ResourceManager;
	}
	// Engine initialization
	public void initialize() {
		Globals.KillSwitch = false;
		Platform_I platform = PlatformFactory.createPlatform(Constants.PLATFORM_TYPE);
		Globals.Platform = platform;
		
		platform.initialize(); 
		
		_Time = new Timer();
		_KeyboardQueue = platform.getKeyboard();
		_AudioManager = new AudioManager(platform.getAudioBuffer());
		_ScreenBuffer = platform.getScreenBuffer();
		
		_MessageSystem = new MessageSystem();
		
		_ResourceManager = new ResourceManager();
		
	}
	private int frameCounter;
	private int frameInterval;
	// Execute one frame of engine logic.
	public void execute() {
		// Update Frame Timer
		_Time.update();
		
		// FPS counting.
		frameInterval += _Time.getElapsed();
		if(frameInterval >= 1000) {
			frameInterval -= 1000;
			Log.debug(Integer.toString(frameCounter));
			frameCounter = 0;
		}
		// Pump game.
		pumpGame(_GameInstance, _Time.getElapsed());
		
		frameCounter++;
		// Pump sound
		_AudioManager.play();
		Globals.Platform.playAudio();
		
		// Pump video
		Globals.Platform.render();
	}

	// Graceful shutdown of all subsystems.
	public void shutDown() {
		if(_GameInstance != null) {
			_GameInstance.shutdown(this);
		}
		if(_NextGameInstance != null) {
			_NextGameInstance.shutdown(this);
		}
		Globals.KillSwitch = true;
		Globals.Platform.shutDown();
	}
}